package session

import (
	"encoding/json"
	"errors"
	"github.com/gomodule/redigo/redis"
	"sync"
)

/*
RedisSession的设计
定义对象
构造函数
实现Session的四个方法
*/
type RedisSession struct {
	sessionId string
	pool    *redis.Pool
	// 设置session 先放在内存 再存到redis
	sessionMap map[string]interface{}
	// 读写锁
	rwlock sync.RWMutex
	// 记录内存中的map是否被操作
	flag int
}

// 记录状态的常量
const (
	// 内存数据没变化
	SessionFlagNone = iota
	// 内存数据有变化
	SessionFlagModify
)

// 构造函数
func NewRedisSession(id string, pool *redis.Pool) *RedisSession {
	return &RedisSession{
		sessionId:  id,
		sessionMap: make(map[string]interface{},32),
		pool:     pool,
		flag:       SessionFlagNone,
	}
}

func (r *RedisSession)Set(Key string, Value interface{}) (err error)  {
	// 加锁
	r.rwlock.Lock()
	defer r.rwlock.Unlock()
	// 设置值
	r.sessionMap[Key] = Value
	// 标记记录
	r.flag = SessionFlagModify
	return
}
func (r *RedisSession)Get(Key string) (value interface{}, err error)  {
	// 加锁
	r.rwlock.Lock()
	defer r.rwlock.Unlock()
	// 取值
	value, ok := r.sessionMap[Key]
	if !ok{
		err = errors.New("key not exists in session")
	}
	return
}
func (r *RedisSession)Del(Key string) (err error)  {
	// 加锁
	r.rwlock.Lock()
	// 释放锁
	defer r.rwlock.Unlock()
	// 删除
	r.flag = SessionFlagModify
	delete(r.sessionMap, Key)
	return
}

// session存储到redis
func (r *RedisSession)Save() (err error) {
	// 加锁
	r.rwlock.Lock()
	defer r.rwlock.Unlock()
	// 若数据没变不需要存
	if r.flag != SessionFlagModify{
		return
	}
	// 内存中的sessionMap序列化
	data, er := json.Marshal(r.sessionMap)
	if er != nil {
		return
	}
	// 获取连接
	conn := r.pool.Get()
	_, err = conn.Do("SET", r.sessionId, string(data))
	// 修改状态
	r.flag = SessionFlagNone
	if err != nil {
		return
	}
	return
}
